package org.oimwrapper.connectors.genericldap;

import org.oimwrapper.connectors.OIMExceptionHandler;

import com.thortech.xl.dataaccess.tcDataProvider;


/**
 * Exchange helper functions for complicated attributes.
 */
public class OIMLdapExchangeUtilities extends OIMLdapUserOperations {
	
	/**
	 * This constructor is the best to use in process task adapters.
	 *
	 * @param ProcessInstanceKey The key value pointing to the current process.  This should be setup as variable of long type in 
	 *	                         the adapter, and mapped to the process instance key in the process definition as found under 
	 *	                         <code>Process Data -&gt; Process Instance</code>.
	 * @param ProcessFormField   The name of the process form field containing the Generic LDAP Server IT Resource that should
	 *                           should be used for the operations.   This should be a literal string of the form 
	 *	                         <code>UD_MYFORM_SERVER</code>.
	 * @param Database           This is a reference to the current database connector, as found under <code>Adapter References -&gt; 
	 *	                         Database Reference</code> in the Adapter Factory.
	 */
	public OIMLdapExchangeUtilities(long ProcessInstanceKey, String ProcessFormField, tcDataProvider Database) {
		super(ProcessInstanceKey, ProcessFormField, Database);
		logger.debug("Entering ::ldapExchangeUtilities()");
		logger.debug("Exiting ::ldapExchangeUtilities()");
	}

	/**
	 * This constructor is the best to use in entity adapters
	 *
	 * @param ITResourceInstanceKey This key value points to the IT resource instance.   This should be setup as 
	 *                              variable of long type in the adapter, and mapped to the IT resource column 
	 *                              on the form in the Data Object Manager.
	 * @param Database              This is a reference to the current database connector, as found under 
	 *                              <code>Adapter References -&gt; Database Reference</code> in the Adapter 
	 *                              Factory.
	 */
	public OIMLdapExchangeUtilities(long ITResourceInstanceKey, tcDataProvider Database) {
		super(ITResourceInstanceKey, Database);
		logger.debug("Entering ::ldapExchangeUtilities()");
		logger.debug("Exiting ::ldapExchangeUtilities()");
	}
	
	/**
	 * Toggles a bit with the exchange allowed protocol settings to enable or disable a type of access
	 * 
	 * @param Username   The username or other uniquely identifying attribute for the user to be removed.
	 * @param AccessType The type of protocl access to toggle.
	 * @param Enable     <code>true</code> if the access should be allowed, or <code>false</code> if
	 *                   the access should be disallowed.
	 * @param Base       The remaineder of the protocolSettings entry that should be used in the case that
	 *                   existing protocol settings are not present.
	 * @return           <code>SUCCESS</code> if the method succeeds, or <code>FAILURE</code> if the 
	 *                   operation fails.  Details about any operational failure are logged to the 
	 *                   system logger as error messages.
	 */
	protected String toggleProtocolSettings(String Username, String AccessType, boolean Enable, String Base) {
		logger.debug("Entering ::toggleProtocolSettings()");
		logger.debug("Username = " + Username);
		logger.debug("AccessType = " + AccessType);
		logger.debug("Enable = " + Boolean.toString(Enable));
		logger.debug("Base = " + Base);
		String result = "FAILURE";
		String base = Base;
		try {
			ldap.connect();
			String dn = getUserDN(Username);
			OIMLdapObject user = ldap.getObject(dn, new String[] {"protocolSettings"});
			String[] protocols = user.getAttribute("protocolSettings");
			for (int i = 0; i < protocols.length; i++) {
				if (protocols[i].toLowerCase().indexOf(AccessType.toLowerCase()) == 0) {
					base = protocols[i].toLowerCase().replaceAll(AccessType.toLowerCase() + "§1", "");
					base = base.replaceAll(AccessType.toLowerCase() + "§0", "");
					OIMLdapObject remove = new OIMLdapObject();
					remove.appendToAttribute("protocolSettings", protocols[i]);
					ldap.removeAttributeValues(dn, remove);
				}
			}
			OIMLdapObject add = new OIMLdapObject();
			String setting =  AccessType + (Enable ? "§1" : "§0") + base;
			add.appendToAttribute("protocolSettings", setting);
			ldap.appendAttributeValue(dn, add);
			logger.info("Successfully set protocolSettings to include " + setting + " on the account " + Username);
			result = "SUCCESS";
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		} finally {
			try {
				if (ldap != null) {
					ldap.disconnect();
				}
			} catch (Exception e) {
				OIMExceptionHandler.handleException(logger, e, getClass());
			}
		}
		logger.debug("result = " + result);
		logger.debug("Exiting ::toggleProtocolSettings()");
		return result;
	}
	
	/**
	 * Enables or disables user access to specific exchange protocol.
	 * 
	 * @param Username   The username or other uniquely identifying attribute for the user to be updated.
	 * @param AccessType The type of protocol access to toggle.  Valid access types are:
	 *                   - IMAP4
	 *                   - POP3
	 *                   - HTTP
	 *                   - ACTIVESYNC
	 *                   - MAPI
	 * @param Enable     <code>TRUE</code> if the access should be allowed, or <code>FALSE</code> if
	 *                   the access should be disallowed.
	 * @return           <code>SUCCESS</code> if the method succeeds, or <code>FAILURE</code> if the 
	 *                   operation fails.  Details about any operational failure are logged to the 
	 *                   system logger as error messages.
	 */
	public String toggleAccess(String Username, String AccessType, String Enable) {
		logger.debug("Entering ::parseAccess()");
		String result = "FAILURE";
		boolean enable = Enable.equalsIgnoreCase("TRUE");
		if (AccessType.equalsIgnoreCase("IMAP4")) {
			result = toggleProtocolSettings(Username, AccessType, enable, "§1§4§ISO-8859-1§0§1§0§0");
		} else if (AccessType.equalsIgnoreCase("POP3")) {
			result = toggleProtocolSettings(Username, AccessType, enable, "§1§4§ISO-8859-1§0§§§");
		} else if (AccessType.equalsIgnoreCase("HTTP")) {
			result = toggleProtocolSettings(Username, AccessType, enable, "§1§§§§§§");
		} else if (AccessType.equalsIgnoreCase("ACTIVESYNC")) {
			result = setAttributeBit(Username, "msExchOmaAdminWirelessEnable", 0x1, !enable);
			if (result.equalsIgnoreCase("SUCCESS")) {
				result = setAttributeBit(Username, "msExchOmaAdminWirelessEnable", 0x2, !enable);
				if (result.equalsIgnoreCase("SUCCESS")) {
					result = setAttributeBit(Username, "msExchOmaAdminWirelessEnable", 0x4, !enable);
					if (result.equalsIgnoreCase("SUCCESS")) {
						logger.info("Successfully set msExchOmaAdminWirelessEnable to include " + Boolean.toString(enable) + " on the account " + Username);
					}
				}
			}
		} else if (AccessType.equalsIgnoreCase("MAPI")) {
			result = toggleProtocolSettings(Username, AccessType, enable, "§0§§§§§§");
		} else {
			logger.warn("Unknown Access Type " + AccessType);
		}
 		logger.debug("Exiting ::parseAccess()");
		return result;
	}
	
	/**
	 * Adds or updates an SMTP address to a user.  If needed, the existing primary address will
	 * be switched to a secondary address.
	 * 
	 * @param Username The username or other uniquely identifying attribute for the user to be updated.
	 * @param Address  The SMTP address to add or update on the user.
	 * @param Primary  <code>true</code> if the address should be a primary address, or 
	 *                 <code>false</code> if the address should be a secondary address.
	 * @return         <code>SUCCESS</code> if the method succeeds, or <code>FAILURE</code> if the 
	 *                 operation fails.  Details about any operational failure are logged to the 
	 *                 system logger as error messages.
	 */
	public String addSmtpAddress(String Username, String Address, String Primary) {
		logger.debug("Entering ::addSmtpAddress()");
		logger.debug("Username = " + Username);
		logger.debug("Address = " + Address);
		logger.debug("Primary = " + Primary);
		String result = "FAILURE";
		try {
			ldap.connect();
			boolean primary = Primary.equalsIgnoreCase("true");
			String dn = getUserDN(Username);
			OIMLdapObject user = ldap.getObject(dn, new String[] {"proxyAddresses", "mail"});
			String[] addresses = user.getAttribute("proxyAddresses");
			boolean add = true;
			for (int i = 0; i < addresses.length; i++) {
				if (addresses[i].toLowerCase().matches("smtp:.*")) {
					boolean isPrimary = addresses[i].substring(0, 4).equals("SMTP:");
					String address = addresses[i].substring(5);
					if (address.equalsIgnoreCase(Address)) {
						if (primary != isPrimary) {
							OIMLdapObject change = new OIMLdapObject();
							change.setAttribute("proxyAddresses", addresses[i]);
							ldap.removeAttributeValues(dn, change);
							logger.info("Successfully removed " + Address + " as an address on the account for " + Username);
						} else {
							add = false;
						}
					} else if (primary && isPrimary) {
						OIMLdapObject change = new OIMLdapObject();
						change.setAttribute("proxyAddresses", addresses[i]);
						ldap.removeAttributeValues(dn, change);
						change = new OIMLdapObject();
						change.setAttribute("proxyAddresses", "smtp:" + address);
						ldap.appendAttributeValue(dn, change);
						logger.info("Successfully switched " + Address + " to a secondary address on the account for " + Username);
					}
				}
			}
			if (add) {
				OIMLdapObject change = new OIMLdapObject();
				change.setAttribute("proxyAddresses", (primary ? "SMTP:" : "smtp:") + Address);
				ldap.appendAttributeValue(dn, change);
				logger.info("Successfully appended " + Address + " as a " + (primary ? "primary" : "secondary") + " address on the account for " + Username);
			}
			if (primary) {
				String mail = "";
				if (user.containsAttribute("mail")) {
					mail = user.getAttribute("mail")[0];
				}
				if (!mail.equals(Address)) {
					OIMLdapObject change = new OIMLdapObject();
					change.setAttribute("mail", Address);
					ldap.setAttributeValue(dn, change);
					logger.info("Successfully set mail to " + Address + " on the account for " + Username);
				}
			}
			result = "SUCCESS";
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		} finally {
			try {
				if (ldap != null) {
					ldap.disconnect();
				}
			} catch (Exception e) {
				OIMExceptionHandler.handleException(logger, e, getClass());
			}
		}
		logger.debug("result = " + result);
		logger.debug("Exiting ::addSmtpAddress()");
		return result;
	}
	
	/**
	 * Removes an SMTP address from a user.   If the Address is the primary address, then
	 * the mail entry will be removed as well as the proxyAddresses entry.
	 * 
	 * @param Username The username or other uniquely identifying attribute for the user to be removed.
	 * @param Address  The SMTP address to remove from the user.
	 * @return         <code>SUCCESS</code> if the method succeeds, or <code>FAILURE</code> if the 
	 *                 operation fails.  Details about any operational failure are logged to the 
	 *                 system logger as error messages.
	 */
	public String removeSmtpAddress(String Username, String Address) {
		logger.debug("Entering ::removeSmtpAddress()");
		logger.debug("Username = " + Username);
		logger.debug("Address = " + Address);
		String result = "FAILURE";
		try {
			ldap.connect();
			String dn = getUserDN(Username);
			OIMLdapObject user = ldap.getObject(dn, new String[] {"proxyAddresses", "mail"});
			String[] addresses = user.getAttribute("proxyAddresses");
			for (int i = 0; i < addresses.length; i++) {
				if (addresses[i].toLowerCase().matches("smtp:.*")) {
					String address = addresses[i].substring(5);
					if (address.equalsIgnoreCase(Address)) {
						OIMLdapObject change = new OIMLdapObject();
						change.setAttribute("proxyAddresses", addresses[i]);
						ldap.removeAttributeValues(dn, change);
						logger.info("Successfully removed " + Address + " as an address on the account for " + Username);
					}
				}
			}
			String mail = "";
			if (user.containsAttribute("mail")) {
				mail = user.getAttribute("mail")[0];
			}
			if (!mail.equalsIgnoreCase(Address)) {
				OIMLdapObject change = new OIMLdapObject();
				change.setAttributeToNull("mail");
				ldap.setAttributeValue(dn, change);
				logger.info("Successfully cleared mail on the account for " + Username);
			}
			result = "SUCCESS";
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		} finally {
			try {
				if (ldap != null) {
					ldap.disconnect();
				}
			} catch (Exception e) {
				OIMExceptionHandler.handleException(logger, e, getClass());
			}
		}
		logger.debug("result = " + result);
		logger.debug("Exiting ::removeSmtpAddress()");
		return result;
	}
}